#pragma once
#include <Rz/Object.h>
#include <Rz/IEquatable.h>
#include <Rz/Graphics/Math/Vector2.h>
#include <Rz/Graphics/Math/Vector3.h>
#include <Rz/Collections/InitializerList.h>
#include <Rz/Collections/List.h>
#include "IVertexDescription.h"
#include "../VertexDescription.h"
#include "../VertexElement.h"

namespace Rz { namespace Graphics { namespace Render { namespace VertexDescriptions {

struct PositionNormalTexture :
	public Object,
	public IVertexDescription,
	public IEquatable<PositionNormalTexture>
{
	RZ_RTTI(Rz::Graphics::Render::VertexDescriptions, PositionNormalTexture);
	RZ_RTTI_IMPLEMENTS(Object, IVertexDescription, IEquatable<PositionNormalTexture>);
	RZ_RTTI_END;

	Math::Vector3 Position;
	Math::Vector3 Normal;
	Math::Vector2 TexCoord;

	PositionNormalTexture()
		: Position(Math::Vector3::Zero)
		, Normal(Math::Vector3::Zero)
		, TexCoord(Math::Vector2::Zero)
	{

	}

	PositionNormalTexture(const Math::Vector3& position)
		: Position(position)
		, Normal(Math::Vector3::Zero)
		, TexCoord(Math::Vector2::Zero)
	{

	}

	PositionNormalTexture(const Math::Vector3& position, const Math::Vector2& texCoord)
		: Position(position)
		, Normal(Math::Vector3::Zero)
		, TexCoord(texCoord)
	{

	}

	PositionNormalTexture(const Math::Vector3& position, const Math::Vector3& normal, const Math::Vector2& texCoord)
		: Position(position)
		, Normal(normal)
		, TexCoord(texCoord)
	{

	}

	RZ_INLINE virtual Collections::SingleCollection GetRawData() const override
	{
		Collections::SingleCollection data(3 * 2 + 2); // sizeof(Vector3) + sizeof(Vector3) + sizeof(Vector2)

		data.Add(Position.Cell, 3);
		data.Add(Normal.Cell, 3);
		data.Add(TexCoord.Cell, 2);

		return data;
	}

	RZ_INLINE virtual const VertexDescription* GetVertexDescription() const override
	{
		return GetVertexDescriptionStatic();
	}

	static VertexDescription* GetVertexDescriptionStatic()
	{
		static Ptr<VertexDescription> vertexDescription;

		if (!vertexDescription)
		{
			Collections::List<VertexElement> vertexElements;
			vertexElements.Add(VertexElement(0,  VertexElementFormat::Vector3, VertexElementUsage::Position,			0));
			vertexElements.Add(VertexElement(12, VertexElementFormat::Vector3, VertexElementUsage::Normal,				0));
			vertexElements.Add(VertexElement(24, VertexElementFormat::Vector2, VertexElementUsage::TextureCoordinate,	0));

			vertexDescription = new VertexDescription(vertexElements);
		}

		return vertexDescription;
	}

	// IEquatable
	virtual bool Equals(const PositionNormalTexture& r) const override
	{
		return (
			this->Position == r.Position &&
			this->Normal == r.Normal &&
			this->TexCoord == r.TexCoord
			);
	}

	virtual bool operator == (const PositionNormalTexture& r) const { return  Equals(r); }
	virtual bool operator != (const PositionNormalTexture& r) const { return !Equals(r); }
};

} } } }
